// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_MACH_BROKER_MAC_H_
#define CONTENT_BROWSER_MACH_BROKER_MAC_H_

#include <map>
#include <string>

#include "base/mac/mach_port_broker.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/process/port_provider_mac.h"
#include "base/process/process_handle.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/browser_child_process_observer.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"

namespace content {

// A global |MachBroker| singleton is used by content embedders to provide
// access to mach task ports for content child processes.
class CONTENT_EXPORT MachBroker : public base::PortProvider,
                                  public BrowserChildProcessObserver,
                                  public NotificationObserver,
                                  public base::PortProvider::Observer {
public:
    // For use in child processes. This will send the task port of the current
    // process over Mach IPC to the port registered by name (via this class) in
    // the parent process. Returns true if the message was sent successfully
    // and false if otherwise.
    static bool ChildSendTaskPortToParent();

    // Returns the global MachBroker.
    static MachBroker* GetInstance();

    // The lock that protects this MachBroker object.  Clients MUST acquire and
    // release this lock around calls to EnsureRunning() and PlaceholderForPid().
    base::Lock& GetLock();

    // Performs any necessary setup that cannot happen in the constructor.
    // Callers MUST acquire the lock given by GetLock() before calling this
    // method (and release the lock afterwards).
    void EnsureRunning();

    // Adds a placeholder to the map for the given pid with MACH_PORT_NULL.
    // Callers MUST acquire the lock given by GetLock() before calling this method
    // (and release the lock afterwards).
    void AddPlaceholderForPid(base::ProcessHandle pid, int child_process_id);

    // Implement |base::PortProvider|.
    mach_port_t TaskForPid(base::ProcessHandle process) const override;

    // Implement |BrowserChildProcessObserver|.
    void BrowserChildProcessHostDisconnected(
        const ChildProcessData& data) override;
    void BrowserChildProcessCrashed(const ChildProcessData& data,
        int exit_code) override;

    // Implement |NotificationObserver|.
    void Observe(int type,
        const NotificationSource& source,
        const NotificationDetails& details) override;

    // Returns the Mach port name to use when sending or receiving messages.
    // Does the Right Thing in the browser and in child processes.
    static std::string GetMachPortName();

private:
    friend class MachBrokerTest;
    friend struct base::DefaultSingletonTraits<MachBroker>;

    MachBroker();
    ~MachBroker() override;

    // Implement |base::PortProvider::Observer|.
    void OnReceivedTaskPort(base::ProcessHandle process) override;

    // Removes all mappings belonging to |child_process_id| from the broker.
    void InvalidateChildProcessId(int child_process_id);

    // Callback used to register notifications on the UI thread.
    void RegisterNotifications();

    // Whether or not the class has been initialized.
    bool initialized_;

    // Used to register for notifications received by NotificationObserver.
    // Accessed only on the UI thread.
    NotificationRegistrar registrar_;

    // Stores the Child process unique id (RenderProcessHost ID) for every
    // process. Protected by base::MachPortBroker::GetLock().
    typedef std::map<int, base::ProcessHandle> ChildProcessIdMap;
    ChildProcessIdMap child_process_id_map_;

    // Underlying port broker that receives and manages mach ports.
    base::MachPortBroker broker_;

    DISALLOW_COPY_AND_ASSIGN(MachBroker);
};

} // namespace content

#endif // CONTENT_BROWSER_MACH_BROKER_MAC_H_
